package com.web.kdl.service.matrix;

import cn.hutool.core.bean.BeanUtil;
import com.web.kdl.common.result.CommonResult;
import com.web.kdl.config.modbus.Modbus4jFactory;
import com.web.kdl.daoV2.matrix.MatrixDao;
import com.web.kdl.entity.matrix.Matrix;
import com.web.kdl.entity.site.Site;
import com.web.kdl.pojo.Bo.MatrixBo;
import com.web.kdl.pojo.Vo.MatrixVo;
import com.web.kdl.pojo.Vo.WheelVo;
import com.web.kdl.pojo.dto.AddMatrixDto;
import com.web.kdl.pojo.dto.UpdateMatrixDto;
import com.web.kdl.service.createTable.ControlTable;
import com.web.kdl.service.createTable.FlywheelTable;
import com.web.kdl.service.createTable.TableDataType;
import com.web.kdl.service.createTable.TableType;
import com.web.kdl.service.createTable.factory.TableFactory;
import com.web.kdl.service.flywheel.FlyWheelService;
import com.web.kdl.service.site.SiteService;
import com.web.kdl.util.TableNameUtils;
import com.web.kdl.util.TopicUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.dao.DataAccessException;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@Service
@Slf4j
@RequiredArgsConstructor
public class MatrixServiceImpl implements MatrixService{

    private final MatrixDao matrixDao;
    private final FlyWheelService flyWheelService;
    private final SiteService siteService;
    private final ControlTable controlTable;
    private final JdbcTemplate jdbcTemplate;
    private final TableFactory tableFactory;
    private final MqttPahoMessageDrivenChannelAdapter mqttInboundAdapter;
    private final Modbus4jFactory  modbus4jFactory;
    private final TransactionTemplate transactionTemplate;

    @Override
    public  CommonResult addMatrix(AddMatrixDto addMatrixDto) {
        log.info("事务是否活跃: {}", TransactionSynchronizationManager.isActualTransactionActive());
        log.info("当前事务: {}", TransactionSynchronizationManager.getCurrentTransactionName());
        synchronized (AopContext.currentProxy()) {
            if (addMatrixDto.getWheelNumber() < 1 || addMatrixDto.getWheelNumber() > 4) {
                return CommonResult.error("阵列下的飞轮数量必须在1~4个之间");
            }
            //判断订阅主题是否合法
            boolean bool = addMatrixDto.getTopic().chars().allMatch(Character::isLetterOrDigit);
            if (!bool) {
                return CommonResult.error("订阅主题只能包含数字和字母");
            }
            //判断该站点下是否存在同名阵列
            List<Matrix> matrices = matrixDao.selectList(null);
            long count = matrices.stream().filter(
                            matrix1 -> matrix1.getSiteId().equals(addMatrixDto.getSiteId()) &&
                                    matrix1.getMatrixName().equals(addMatrixDto.getMatrixName()))
                    .count();
            if (count > 0) {
                log.info("该站点已存在同名阵列");
                return CommonResult.error("该站点已存在同名阵列");
            }
            //判断订阅主题是否重复
            long count1 = matrices.stream().filter(matrix1 -> matrix1.getTopic().equals(addMatrixDto.getTopic())).count();
            if (count1 > 0) {
                return CommonResult.error("订阅主题已经被其他阵列使用");
            }
            //获取站点信息，用于构建总控表和飞轮表
            Site site = siteService.getSiteById(addMatrixDto.getSiteId());
            if (site == null) {
                return CommonResult.error("该站点不存在, 站点id: " + addMatrixDto.getSiteId());
            }
            String siteName = site.getSumSite();
            String matrixName = addMatrixDto.getMatrixName();
            List<String> createdTables = new ArrayList<>();
            AtomicReference<String> topic = new AtomicReference<>();
            try {
                //创建总控表 站点名_阵列名
                String controlDataTableName = TableNameUtils.getControlDataTableName(siteName, matrixName);
                String createDataSql = controlTable.getCreateDataTableSql(controlDataTableName);
                jdbcTemplate.execute(createDataSql);
                createdTables.add(controlDataTableName);

                String controlAlertTableName = TableNameUtils.getControlAlertTableName(siteName, matrixName);
                String createAlertSql = controlTable.getCreateAlertTableSql(controlAlertTableName);
                jdbcTemplate.execute(createAlertSql);
                createdTables.add(controlAlertTableName);

                String controlStatusTableName = TableNameUtils.getControlStatusTableName(siteName, matrixName);
                String createStatusSql = controlTable.getCreateStatusTableSql(controlStatusTableName);
                jdbcTemplate.execute(createStatusSql);
                createdTables.add(controlStatusTableName);

                //创建飞轮alert,status表 站点名_阵列名_飞轮名
                for (Integer i = 0; i < addMatrixDto.getWheelNumber(); i++) {
                    String flywheelName = "flywheel" + (i + 1);
                    for (TableType type : TableType.values()) {
                        FlywheelTable table = tableFactory.createTable(siteName, matrixName, flywheelName, type);
                        jdbcTemplate.execute(table.createTable());
                        createdTables.add(table.getTableName());
                    }
                    //创建飞轮data表 day temp hour
                    for (TableDataType type : TableDataType.values()) {
                        FlywheelTable table = tableFactory.createDataTable(siteName, matrixName, flywheelName, type);
                        jdbcTemplate.execute(table.createTable());
                        createdTables.add(table.getTableName());
                    }
                }

                return transactionTemplate.execute(status -> {
                    try {
                        // 插入阵列信息
                        Matrix matrix = new Matrix();
                        BeanUtil.copyProperties(addMatrixDto, matrix);
                        int insert = matrixDao.insert(matrix);
                        if (insert <= 0) {
                            throw new RuntimeException("添加阵列失败");
                        }

                        topic.set(TopicUtils.getSubscribeTopic(matrix.getTopic()));
                        mqttInboundAdapter.addTopic(topic.get(),
                                1);
                        log.info("动态添加订阅: {}", topic);

                        return CommonResult.success("添加成功");
                    } catch (Exception e) {
                        status.setRollbackOnly();
                        throw new RuntimeException("数据操作失败: " + e.getMessage(), e);
                    }
                });
            } catch (Exception e) {
                // 出现异常 → 删除已经创建的表
                for (String tableName : createdTables) {
                    try {
                        String deleteTableSql = controlTable.getDeleteSql(tableName);
                        jdbcTemplate.execute(deleteTableSql);
                    } catch (Exception ex) {
                        // 日志记录，人工清理
                        log.error("删除表{}失败,错误信息：{} ", tableName, ex.getMessage(), ex);
                    }
                }
                mqttInboundAdapter.removeTopic(topic.get()); //移除订阅主题
                throw new RuntimeException("添加失败: " + e.getMessage(), e);
            }
        }
    }
    @Override
    public CommonResult deleteMatrix(Integer id) {
        Matrix matrix = matrixDao.selectById(id);
        if (matrix == null) {
            return CommonResult.error("该阵列不存在, 阵列id: " + id);
        }

        // 获取站点信息
        Site site = siteService.getSiteById(matrix.getSiteId());

        // 删除总控表
        String[] controlTableNames = controlTable.getControlTableName(site.getSumSite(), matrix.getMatrixName());
        for (String tableName : controlTableNames) {
            try {
                String deleteSql = controlTable.getDeleteSql(tableName);
                jdbcTemplate.execute(deleteSql);
            } catch (DataAccessException e) {
                log.error("删除总控表 {} 失败, 错误信息：{}", tableName, e.getMessage(), e);
            }
        }

        // 删除飞轮表
        for (int i = 1; i <= matrix.getWheelNumber(); i++) {
            String flywheelName = "flywheel" + i;
            for (TableType type : TableType.values()) {
                FlywheelTable table = tableFactory.deleteTable(site.getSumSite(), matrix.getMatrixName(), flywheelName, type);
                try {
                    jdbcTemplate.execute(table.deleteTable());
                } catch (DataAccessException e) {
                    log.error("删除飞轮表 {} 失败, 错误信息：{}", table.getTableName(), e.getMessage(), e);
                }
            }
            //删除飞轮data表 day temp hour
            for (TableDataType type: TableDataType.values()){
                FlywheelTable table = tableFactory.deleteDataTable(site.getSumSite(), matrix.getMatrixName(), flywheelName, type);
                try {
                    jdbcTemplate.execute(table.deleteTable());
                } catch (DataAccessException e) {
                    log.error("删除飞轮数据表 {} 失败, 错误信息：{}", table.getTableName(), e.getMessage(), e);
                }
            }
        }

        int i = matrixDao.deleteById(id);
        if (i <= 0) {
            return CommonResult.error("删除阵列失败");
        }
        String topic = TopicUtils.getSubscribeTopic(matrix.getTopic());
        mqttInboundAdapter.removeTopic(topic);
//        modbus4jFactory.closeConnection(String.valueOf(matrix.getId()), matrix.getIp(), matrix.getPort());
        log.info("删除订阅: {}", topic);
        return CommonResult.success("删除成功");
    }

    @Override
    public CommonResult getMatrixList() {
        //      获取 SiteWheel 表中 sumSite 去重列 按照sum_site 升序
        ArrayList<WheelVo> wheelVos = new ArrayList<>();
        List<MatrixBo> matrixList = matrixDao.selectMatrixTable();
        for(MatrixBo matrixBo : matrixList){
            for (int i = 1; i <=matrixBo.getFlywheelSerial() ; i++) {
                WheelVo wheelVo = new WheelVo(matrixBo.getMatrixId(), matrixBo.getSiteName(), matrixBo.getMatrixName(), "flywheel" + i);
                wheelVos.add(wheelVo);
            }
        }
        return CommonResult.success(wheelVos);
    }

    @Override
    @Transactional
    public CommonResult updateMatrix(UpdateMatrixDto updateMatrixDto) {
        if(updateMatrixDto.getWheelNumber()<1|| updateMatrixDto.getWheelNumber()>4){
            return CommonResult.error("阵列下的飞轮数量必须在1~4个之间");
        }
        //判断订阅主题是否合法
        boolean bool = updateMatrixDto.getTopic().chars().allMatch(Character::isLetterOrDigit);
        if(!bool){
            return CommonResult.error("订阅主题只能包含数字和字母");
        }
        Matrix matrix = matrixDao.selectById(updateMatrixDto.getMatrixId());
        if(matrix == null){
            return CommonResult.error("该阵列不存在, 阵列id: " + updateMatrixDto.getMatrixId());
        }
        if(!matrix.getMatrixName().equals(updateMatrixDto.getMatrixName())){
            return CommonResult.error("阵列名称不能修改");
        }
        //判断该站点下是否存在同名阵列
        List<Matrix> matrices = matrixDao.selectList(null);
        long count = matrices.stream().filter(
                        matrix1 -> matrix1.getSiteId().equals(updateMatrixDto.getSiteId()) &&
                                matrix1.getMatrixName().equals(updateMatrixDto.getMatrixName()) &&
                                !matrix1.getId().equals(updateMatrixDto.getMatrixId())
                )
                .count();
        if(count > 0){
            return CommonResult.error("该站点已存在同名阵列");
        }
        //判断订阅主题是否重复
        long count1 = matrices.stream().filter(
                    matrix1 -> matrix1.getTopic().equals(updateMatrixDto.getTopic()) &&
                    !matrix1.getId().equals(updateMatrixDto.getMatrixId())
                ).count();
        if(count1 > 0){
            return CommonResult.error("订阅主题已经被其他阵列使用");
        }

        //获取站点名称
        Site site = siteService.getSiteById(updateMatrixDto.getSiteId());
        if(site==null) {
            return CommonResult.error("该站点不存在, 站点id: " + updateMatrixDto.getSiteId());
        }


        String siteName = site.getSumSite();
        String matrixName = matrix.getMatrixName();

        //若更新后的飞轮数量大于之前的飞轮数据，则添加飞轮表
        if (updateMatrixDto.getWheelNumber() > matrix.getWheelNumber()) {
            List<String> createdTables = new ArrayList<>();

            try {
                for(int i=matrix.getWheelNumber();i<updateMatrixDto.getWheelNumber();i++){
                    String flywheelName =  "flywheel"+(i+1);
                    for (TableType type:TableType.values()){
                        FlywheelTable table = tableFactory.createTable(siteName,matrixName, flywheelName, type);
                        jdbcTemplate.execute(table.createTable());
                        createdTables.add(table.getTableName());
                    }
                    //创建飞轮data表 day temp hour
                    for (TableDataType type: TableDataType.values()){
                        FlywheelTable table = tableFactory.createDataTable(siteName,matrixName, flywheelName, type);
                        jdbcTemplate.execute(table.createTable());
                        createdTables.add(table.getTableName());
                    }
                }

            } catch (DataAccessException e) {
                // 出现异常 → 删除已经创建的表
                for (String tableName : createdTables) {
                    try {
                        String deleteTableSql = controlTable.getDeleteSql(tableName);
                        jdbcTemplate.execute(deleteTableSql);
                    } catch (Exception ex) {
                        // 日志记录，人工清理
                        log.error("删除表{}失败,错误信息：{} " ,tableName, ex.getMessage(), ex);
                    }
                }
                throw new RuntimeException("添加失败: " + e.getMessage(), e);
            }
        }
        //若更新后的飞轮数量小于之前的飞轮数据，则删除飞轮表
        if(updateMatrixDto.getWheelNumber() < matrix.getWheelNumber()){
            for(int i=updateMatrixDto.getWheelNumber();i<matrix.getWheelNumber();i++){
                String flywheelName =  "flywheel"+(i+1);
                //删除飞轮表 alert status
                for (TableType type:TableType.values()){
                    FlywheelTable table = tableFactory.createTable(siteName,matrixName, flywheelName, type);
                    try {
                        jdbcTemplate.execute(table.deleteTable());
                    } catch (DataAccessException e) {
                        log.error("删除飞轮表 {} 失败, 错误信息：{}", table.getTableName(), e.getMessage(), e);
                    }
                }
                //删除飞轮data表 day temp hour
                for (TableDataType type: TableDataType.values()){
                    FlywheelTable table = tableFactory.deleteDataTable(site.getSumSite(), matrix.getMatrixName(), flywheelName, type);
                    try {
                        jdbcTemplate.execute(table.deleteTable());
                    } catch (DataAccessException e) {
                        log.error("删除飞轮数据表 {} 失败, 错误信息：{}", table.getTableName(), e.getMessage(), e);
                    }
                }
            }
        }
        Matrix matrix1 = new Matrix();
        BeanUtil.copyProperties(updateMatrixDto, matrix1);
        matrix1.setId(updateMatrixDto.getMatrixId());
        matrixDao.updateById(matrix1);
//        modbus4jFactory.reconnectDevice(String.valueOf(updateMatrixDto.getMatrixId()), updateMatrixDto.getIp(), updateMatrixDto.getPort());
        if(!matrix.getTopic().equals(matrix1.getTopic())){ //订阅主题修改
            mqttInboundAdapter.addTopic(matrix1.getTopic(), 1); //添加新订阅
            mqttInboundAdapter.removeTopic(matrix.getTopic()); //删除旧订阅
        }

        return CommonResult.success("更新成功");
    }

    @Override
    public CommonResult getMatrixById(Integer id) {
        MatrixVo matrixVo = matrixDao.selectMatrixById(id);
        if (matrixVo == null){
            return CommonResult.error("该阵列不存在");
        }
        return CommonResult.success(matrixVo);
    }
}
